package comp5511.project04;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class Trie {
	
	private String noiseWordsFile = "src/ds13s-asg4-noise-words.txt";
	
	private HashSet<String> noiseWords = new HashSet<String>();
	
	private HashSet<String> symbolSet = new HashSet<String>();
	
	private TrieNode root;
	
	public Trie(){
		root = new TrieNode();
		//
		symbolSet.add(",");
		symbolSet.add(".");
		symbolSet.add(":");
		symbolSet.add("\"");
		
		//read noise words
		BufferedReader reader = null;
		try{
			reader = new BufferedReader(new FileReader(noiseWordsFile));
			String line;
			while (((line = reader.readLine()) != null)) {
				String[] words = line.split(",");
				for(String word : words){
					word = word.trim();
					if((!word.equals(""))){
						noiseWords.add(word);
					}
				}
			}
			System.out.println("total noise words:" + noiseWords.size());
		}
		catch(Exception e){
			System.out.println("fail when loading noise words!");
		}
		finally{
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void addWord(String word, Paper paper){
		addWord(root, word, paper);
	}

	private void addWord(TrieNode node, String word, Paper paper){
		if(word.length() == 0){
			node.setWords(node.getWords()+1);
			List<Paper> list = node.getPaperList();
			if(list==null){
				list = new ArrayList<Paper>();
				node.setPaperList(list);
			}
			list.add(paper);
		}
		else{
			node.setPrefixes(node.getPrefixes()+1);
			char c = word.charAt(0);
			c = Character.toLowerCase(c);
			int index = c;
			if(node.getChildren()[index] == null){
				node.setChildren(index, new TrieNode());
			}
			addWord(node.getChildren()[index], word.substring(1), paper);
		}
	}
	
	public void index(String inputFile) throws Exception{
		BufferedReader reader = null;
		try{
			reader = new BufferedReader(new FileReader(inputFile));
			String line;
			int number=0;
			while (((line = reader.readLine()) != null)) {
				number++;
				//ignore first line
				if(number==1){
					continue;
				}
				String[] strArray = line.split("\\|");
				String pid = strArray[1].trim();
				String title = strArray[2].trim();
				String[] authors = strArray[3].trim().split(";");
				String[] keywords = strArray[4].trim().split(",");
				String path = strArray[5].trim();
				Paper paper = new Paper(pid, title, authors, keywords, path);
				for(String item: title.split(" ")){
					item = item.trim();
					item = trimSymbol(item);
					if(item==null || item.length()==0){
						continue;
					}
					if(noiseWords.contains(item)){
						continue;
					}
					addWord(item,paper);
				}
			}
			System.out.println("indexing finished");
		}
		catch(Exception e){
			System.out.println("fail when creating index");
			throw e;
		}
		finally{
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private List<Paper> search(TrieNode node, String word){
		if(word.length()==0){
			return node.getPaperList();
		}
		char c = word.charAt(0);
		c = Character.toLowerCase(c);
		int index = c;
		if(node.getChildren()[index] == null){
			return null;
		}
		else{
			return search(node.getChildren()[index], word.substring(1));
		}
	}
	
	public List<Paper> search(String words){
		String[] wordArray = words.split(" ");
		List<List<Paper>> list = new ArrayList<List<Paper>>();
		for(String word: wordArray){
			list.add(search(root, word.trim()));
		}
		
		return and(list);
	}
	
	private List<Paper> and(List<List<Paper>> list){
		if(list==null|| list.size()==0){
			return null;
		}
		else if(list.size()==1){
			return list.get(0);
		}
		else{
			if(list.get(0)==null|| list.get(0).size()==0){
				return null;
			}
			else{
				List<Paper> result = new ArrayList<Paper>();
				for(Paper paper: list.get(0)){
					if(contains(paper, list.subList(1, list.size()))){
						result.add(paper);
					}
				}
				return result;
			}
		}
	}
	
	private boolean contains(Paper paper, List<List<Paper>> list){
		boolean flag = true;
		for(List<Paper> sublist: list){
			if(!sublist.contains(paper)){
				flag = false;
				break;
			}
		}
		return flag;
	}
	
	public String trimSymbol(String word){
		int beginIndex = 0;
		int endIndex = word.length();
		for(int i=0;i<word.length();i++){
			if(word.charAt(i)<'A' || word.charAt(i)>'z'){
				beginIndex++;
			}
			else{
				break;
			}
		}
		for(int i=word.length()-1;i>=0;i--){
			if(word.charAt(i)<'A' || word.charAt(i)>'z'){
				endIndex--;
			}
			else{
				break;
			}
		}
		if(beginIndex>=endIndex){
			return null;
		}
		else{
			return word.substring(beginIndex, endIndex);
		}
	}
	
}
